
#ifndef _MECHMANIA_COMMON_HEADER_
#define _MECHMANIA_COMMON_HEADER_

#include <typeinfo>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>

#include <libxml/parser.h>
#include <libxml/tree.h>

namespace mm14
{
using std::string;

template<typename T>
T xml_cast(xmlNode *n)
{
	T data;
	std::stringstream ss;
	ss << (char*)n->content;
	ss >> data;
	return data;
}

template<>
string xml_cast(xmlNode *n)
{
	return string((char*)n->content);
}

template<>
int xml_cast(xmlNode *n)
{
	return atoi((char*)n->content);
}

template<>
bool xml_cast(xmlNode *n)
{
	static std::map<string, bool> map;
	if( map.empty() )
	{
		map["true"] = true;
		map["True"] = true;
		map["T"] = true;
		map["t"] = true;
		map["1"] = true;
		map["false"] = false;
		map["False"] = false;
		map["F"] = false;
		map["f"] = false;
		map["0"] = false;
	}
	return map[string((char*)n->content)];
}


template <typename T>
struct _FieldBase
{
	virtual void SetValue(T &object, xmlNode *node) { }
};


template <typename T, typename MT>
class _Field : public _FieldBase<T>
{
private:
	MT T::*_member;

public:
	_Field(MT T::*member):_member(member){ }

	virtual void SetValue(T &object, xmlNode *node)
	{
		object.*_member = xml_cast<MT>(node);
	}

};


template <typename T, typename MT>
class _FieldSet : public _FieldBase<T>
{
private:
	std::vector<MT> T::*_member;

public:
	_FieldSet(std::vector<MT> T::*member):_member(member){ }

	virtual void SetValue(T &object, xmlNode *node)
	{
		(object.*_member).push_back(xml_cast<MT>(node));
	}

};

template <typename T, typename MT>
_FieldSet<T, MT> *FieldSet(std::vector<MT> T::*_member)
{
	return new _FieldSet<T, MT>(_member);
}

template <typename T, typename MT>
_Field<T, MT> *Field(MT T::*_member)
{
	return new _Field<T, MT>(_member);
}


template <typename T>
class Mapper
{
private:
	std::map<std::string, void*> attribs;
	std::map<std::string, void*> elems;

public:
	void addAttribute(std::string s, _FieldBase<T> *f) { attribs[s] = f; }
	void addElement(std::string s, _FieldBase<T> *f) { elems[s] = f; }

	bool initialized() { return elems.empty() && attribs.empty(); }
	
	void parseXml(T &object, xmlNode *n)
	{
		if( n->children )
		{
			for(xmlNode *i=n->children; i; i = i->next)
			{
				if( i->type == XML_ELEMENT_NODE )
				{
					string n = string((char*)i->name);
					_FieldBase<T> *x = (_FieldBase<T>*)elems[n];
					if( x )
					{
						x->SetValue(object, i);
					}
				}
			}
		}

		for(xmlAttr *i=n->properties; i; i = i->next)
		{
			xmlNode *c = i->children;
			if( c->type == XML_TEXT_NODE ){
				string n = string((char*)i->name);
				_FieldBase<T> *x = (_FieldBase<T>*)attribs[n];
				if( x )
				{
					x->SetValue(object, c);
				}
			}
		}

	}

	void destructor_helper()
	{
		std::map<std::string, void*>::iterator i;
		for( i = attribs.begin(); i != attribs.end(); ++i )
		{
			delete (_FieldBase<T>*)(*i).second;
		}
		for( i = elems.begin(); i != elems.end(); ++i )
		{
			delete (_FieldBase<T>*)(*i).second;
		}
	}

	~Mapper()
	{
		destructor_helper();
	}

};


class Object
{
protected:

	string _tag_name;

public:
	Object() { }

	Object(string name) : _tag_name(name) { }

	Object(xmlNode *&node)
	{
		_tag_name = string((char*)node->name);
	}

};

}

#endif
